<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.4.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"yuzhenxin.gitee.io","root":"/","scheme":"Muse","version":"7.8.0","exturl":false,"sidebar":{"position":"right","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":true},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}};
  </script>

  <meta name="description" content="Java基础安装JAVA_HOME: D:\Programming\Java\jdk1.8.0_281 CLASSPATH: .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar; Path: %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin JDK、JRE和JVM JVMJVM的内存结构">
<meta property="og:type" content="article">
<meta property="og:title" content="Java基础">
<meta property="og:url" content="http://yuzhenxin.gitee.io/2020/10/15/Java%E5%9F%BA%E7%A1%80/index.html">
<meta property="og:site_name" content="余振鑫的Hexo博客">
<meta property="og:description" content="Java基础安装JAVA_HOME: D:\Programming\Java\jdk1.8.0_281 CLASSPATH: .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar; Path: %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin JDK、JRE和JVM JVMJVM的内存结构">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://gitee.com/yuzhenxin/images/raw/master/img/20210314220455.png">
<meta property="og:image" content="https://i.imgur.com/ZKBo8pD.png">
<meta property="og:image" content="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223301.png">
<meta property="og:image" content="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223325.png">
<meta property="og:image" content="https://gitee.com/yuzhenxin/images/raw/master/img/20210316161128.png">
<meta property="og:image" content="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223405.png">
<meta property="og:image" content="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223434.png">
<meta property="og:image" content="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223509.png">
<meta property="og:image" content="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223528.png">
<meta property="og:image" content="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223547.png">
<meta property="og:image" content="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223615.png">
<meta property="og:image" content="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223644.png">
<meta property="og:image" content="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223721.png">
<meta property="article:published_time" content="2020-10-14T16:00:00.000Z">
<meta property="article:modified_time" content="2022-01-18T15:07:20.875Z">
<meta property="article:author" content="余振鑫">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://gitee.com/yuzhenxin/images/raw/master/img/20210314220455.png">

<link rel="canonical" href="http://yuzhenxin.gitee.io/2020/10/15/Java%E5%9F%BA%E7%A1%80/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>Java基础 | 余振鑫的Hexo博客</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">余振鑫的Hexo博客</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">计算机笔记</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
  </ul>
</nav>




</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://yuzhenxin.gitee.io/2020/10/15/Java%E5%9F%BA%E7%A1%80/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="余振鑫">
      <meta itemprop="description" content="余振鑫的个人博客">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="余振鑫的Hexo博客">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          Java基础
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-10-15 00:00:00" itemprop="dateCreated datePublished" datetime="2020-10-15T00:00:00+08:00">2020-10-15</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-01-18 23:07:20" itemprop="dateModified" datetime="2022-01-18T23:07:20+08:00">2022-01-18</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h1 id="Java基础"><a href="#Java基础" class="headerlink" title="Java基础"></a>Java基础</h1><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p>JAVA_HOME: D:\Programming\Java\jdk1.8.0_281</p>
<p>CLASSPATH: .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;</p>
<p>Path: %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin</p>
<h2 id="JDK、JRE和JVM"><a href="#JDK、JRE和JVM" class="headerlink" title="JDK、JRE和JVM"></a>JDK、JRE和JVM</h2><p><img src="https://gitee.com/yuzhenxin/images/raw/master/img/20210314220455.png" alt="image-20210314220448618"></p>
<h2 id="JVM"><a href="#JVM" class="headerlink" title="JVM"></a>JVM</h2><h3 id="JVM的内存结构"><a href="#JVM的内存结构" class="headerlink" title="JVM的内存结构"></a>JVM的内存结构</h3><p><img src="https://i.imgur.com/ZKBo8pD.png"></p>
<img src="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223301.png" alt="image-20210223221957681" style="zoom:50%;" />

<img src="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223325.png" alt="image-20210223221715303" style="zoom:50%;" />

<ul>
<li><strong>堆内存</strong>：保存的是对象的具体信息，在程序之中堆内存空间的开辟是通过new完成的（<strong>gc发生地</strong>），该区域是被线程共享的</li>
<li><strong>栈内存</strong>：栈的结构是<strong>栈帧</strong>组成的，调用一个方法就压入一帧，帧上面存储<strong>局部变量表</strong>、操作数栈、方法出口等信息，局部变量表存放的是 <strong>8 大基础类型</strong>加上一个应用类型，所以还是一个指向<strong>堆内存的地址（对象的引用）</strong>，即：通过地址找到堆内存，而后找到对象内容（<strong>基本数据类型在此分配</strong>）</li>
<li><strong>方法区</strong>：主要是存储类信息，常量池（static 常量和 static 变量），编译后的代码（字节码）等数据，该区域是被线程共享的</li>
<li>本地方法栈：主要为 Native 方法服务</li>
<li>程序计数器：记录当前线程执行的行号</li>
</ul>
<h3 id="JVM垃圾回收机制"><a href="#JVM垃圾回收机制" class="headerlink" title="JVM垃圾回收机制"></a>JVM垃圾回收机制</h3><p>没有任何栈内存所指向的堆内存空间为<strong>垃圾空间</strong>，将被GC定期回收</p>
<ul>
<li><p>回收机制</p>
<p>在 Java 中，程序员是不需要显示的去释放一个对象的内存的，而是由虚拟机自行执行。在 JVM 中，有一个垃圾回收线程，它是低优先级的，在正常情况下是不会执行的，只有在<strong>虚拟机空闲或者当前堆内存不足</strong>时，才会触发执行，扫面那些没有被任何引用的对象，并将 它们添加到要回收的集合中，进行回收。</p>
</li>
<li><p>地点：发生在堆(heap)里</p>
</li>
<li><p>分类：</p>
<ol>
<li>收集频繁的Young区</li>
<li>较少收集的Old区</li>
<li>基本不动Perm区</li>
</ol>
</li>
<li><p>GC判定算法</p>
<ul>
<li><p>引用计数法（被淘汰，不能解决相互引用的问题）</p>
</li>
<li><p>可达性分析：从GCRoot开始向下搜索形成引用链，当一个对象没有与任何引用链相连，则不可用，应回收（不是一次判断就回收，首先判断对象是否覆盖finalize()，<strong>未覆盖则回收</strong>；若覆盖未执行，则放入F-Queue，执行finalize()，执行后再判断对象是否可达，可达则复活，不可达就回收）（finalize()代价高，一般不覆盖）</p>
<p>GCRoot对象有：栈中引用的对象，方法区中类静态属性引用的对象，方法区中常量引用的对象，本地方法栈（Native方法）引用对象</p>
</li>
</ul>
</li>
<li><p>GC收集方法</p>
<ol>
<li><p>复制算法：年轻代使用Minor GC。将可用内存按容量划分为相等的两部分，然后每次只使用其中的一块，当一块内存用完时，就将还存活的对象复制到第二块内存上，然后一次性清楚完第一块内存，再将第二块上的对象复制到第一块</p>
<ul>
<li>优点：没有标记清除，效率高；没有内存碎片</li>
<li>缺点：需要双倍空间</li>
<li>改进：每次都会优先使用 Eden 区，若 Eden 区满，就将对象复制到第二块内存区上，然后清除 Eden 区，如果此时存活的对象太多，以至于 Survivor 不够时，会将这些对象通过分配担保机制复制到老年代中。</li>
</ul>
</li>
<li><p>标记清除：老年代使用Full GC</p>
<ul>
<li>优点：无需额外空间</li>
<li>缺点：两次扫描，耗时严重；会产生内存碎片</li>
</ul>
</li>
<li><p>标记压缩：老年代使用Full GC</p>
<ul>
<li>优点：没有内存碎片</li>
<li>缺点：需要移动对象的成本</li>
</ul>
</li>
<li><p>标记清除压缩：上述两种结合</p>
<ul>
<li>优点：减少移动对象成本</li>
</ul>
</li>
</ol>
</li>
</ul>
<h3 id="堆的分区"><a href="#堆的分区" class="headerlink" title="堆的分区"></a>堆的分区</h3><p>分类：</p>
<ul>
<li>新生代（8：1：1）<ul>
<li>Eden区（8）</li>
<li>Survivor区（1+1）<ul>
<li>from区</li>
<li>to区</li>
</ul>
</li>
</ul>
</li>
<li>老生代</li>
</ul>
<h2 id="类加载器"><a href="#类加载器" class="headerlink" title="类加载器"></a>类加载器</h2><ol>
<li>BootstrapClassLoader是ExtClassLoader的父类加载器（非继承，属性parent），加载%JAVA_HOME%\lib下的jar包和class文件</li>
<li>ExtClassLoader是AppClassLoader的父类加载器，加载%JAVA_HOME%\lib\ext下的jar包和class文件</li>
<li>AppClassLoader是系统类加载器，加载classpath下的类文件，通常继承它实现自定义类加载器</li>
</ol>
<h3 id="双亲委托模型"><a href="#双亲委托模型" class="headerlink" title="双亲委托模型"></a>双亲委托模型</h3><p><img src="https://gitee.com/yuzhenxin/images/raw/master/img/20210316161128.png" alt="image-20210316161128315"></p>
<p>好处：</p>
<ul>
<li>安全性，避免用户写的类替换Java核心类，如String（自己写的无效）</li>
<li>避免类的重复加载，JVM区分不同类依靠<strong>类名和类加载器</strong></li>
</ul>
<h2 id="String"><a href="#String" class="headerlink" title="String"></a>String</h2><h3 id="String、StringBuilder、StringBuffer的比较"><a href="#String、StringBuilder、StringBuffer的比较" class="headerlink" title="String、StringBuilder、StringBuffer的比较"></a>String、StringBuilder、StringBuffer的比较</h3><ul>
<li>操作数量较少的字符串用String，不可修改的字符串；</li>
<li>在单线程且操作大量字符串用StringBuilder，速度快，但线程不安全，可修改；</li>
<li>在多线程且操作大量字符串用StringBuffer，<strong>线程安全</strong>（每个方法加了synchronized），可修改。</li>
</ul>
<p>String不可修改，如下则会创建多个垃圾空间，不可取！</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">String str = <span class="string">&quot;www.&quot;</span>;</span><br><span class="line">str += <span class="string">&quot;mldn.&quot;</span>;</span><br><span class="line">str = str+<span class="string">&quot;cn&quot;</span>;</span><br><span class="line">System.out.println(str);</span><br></pre></td></tr></table></figure>

<img src="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223405.png" alt="image-20210223221847696" style="zoom: 50%;" />

<h3 id="字符串常量池"><a href="#字符串常量池" class="headerlink" title="字符串常量池"></a>字符串常量池</h3><p>String的intern()方法：HotSpot VM里，记录interned string的一个全局表叫做StringTable，它本质上就是个HashSet。注意它只存储对java.lang.String实例的引用，而不存储String对象的内容。</p>
<p><strong>字符串常量池只存储引用，不存储内容！</strong></p>
<ul>
<li>如果常量池中存在当前字符串，那么直接返回常量池中它的引用。</li>
<li>如果常量池中没有此字符串, 会将此字符串引用保存到常量池中后, 再直接返回该字符串的引用！</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyTest</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">test1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 字符串常量池的StringTable表指向&quot;1&quot;，栈的s1指向new String(&quot;1&quot;)</span></span><br><span class="line">        String s1 = <span class="keyword">new</span> String(<span class="string">&quot;1&quot;</span>);</span><br><span class="line">        <span class="comment">// 字符串常量池已指向&quot;1&quot;，返回指向&quot;1&quot;的引用，但s1没有接收此新的引用</span></span><br><span class="line">        s1.intern();</span><br><span class="line">        <span class="comment">// 字符串常量池已指向&quot;1&quot;，返回指向&quot;1&quot;的引用给s2</span></span><br><span class="line">        String s2 = <span class="string">&quot;1&quot;</span>;</span><br><span class="line">        System.out.println(s1 == s2); <span class="comment">// false</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 堆中开辟两个new String(&quot;1&quot;)和一个new String(&quot;11&quot;)，s3指向后者</span></span><br><span class="line">        String s3 = <span class="keyword">new</span> String(<span class="string">&quot;1&quot;</span>) + <span class="keyword">new</span> String(<span class="string">&quot;1&quot;</span>);</span><br><span class="line">        <span class="comment">// 字符串常量池没有指向&quot;11&quot;，于是增加指向new String(&quot;11&quot;)，并返回此引用，但s3没有接受此相同的引用</span></span><br><span class="line">        s3.intern();</span><br><span class="line">        <span class="comment">// 字符串常量池指向new String(&quot;11&quot;)，返回该引用给s4</span></span><br><span class="line">        String s4 = <span class="string">&quot;11&quot;</span>;</span><br><span class="line">        System.out.println(s3 == s4); <span class="comment">// true</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">test2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        String s1 = <span class="keyword">new</span> String(<span class="string">&quot;1&quot;</span>);</span><br><span class="line">        String s2 = <span class="string">&quot;1&quot;</span>;</span><br><span class="line">        s1.intern();</span><br><span class="line">        System.out.println(s1 == s2); <span class="comment">// false</span></span><br><span class="line"></span><br><span class="line">        String s3 = <span class="keyword">new</span> String(<span class="string">&quot;1&quot;</span>) + <span class="keyword">new</span> String(<span class="string">&quot;1&quot;</span>);</span><br><span class="line">        <span class="comment">// 字符串常量池不存在&quot;11&quot;，在堆中开辟&quot;11&quot;并指向它，返回此引用给s4</span></span><br><span class="line">        String s4 = <span class="string">&quot;11&quot;</span>;</span><br><span class="line">        s3.intern();</span><br><span class="line"><span class="comment">//       s3 = s3.intern(); //此行执行，结果就是true</span></span><br><span class="line">        System.out.println(s3 == s4); <span class="comment">// false</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// s1 == s3 == s4 !=s2</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">test3</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 堆中开辟5个空间，s1指new String(&quot;hello&quot;)</span></span><br><span class="line">        String s1 = <span class="keyword">new</span> String(<span class="string">&quot;he&quot;</span>) + <span class="keyword">new</span> String(<span class="string">&quot;llo&quot;</span>);</span><br><span class="line">        <span class="comment">// 堆中开辟5个空间，s2指new String(&quot;hello&quot;)，但s1!=s2</span></span><br><span class="line">        String s2 = <span class="keyword">new</span> String(<span class="string">&quot;h&quot;</span>) + <span class="keyword">new</span> String(<span class="string">&quot;ello&quot;</span>);</span><br><span class="line">        <span class="comment">// 字符串常量池指向s1的指向，引用赋给s3</span></span><br><span class="line">        String s3 = s1.intern();</span><br><span class="line">        <span class="comment">// 字符串常量池的指向赋给s4</span></span><br><span class="line">        String s4 = s2.intern();</span><br><span class="line">        System.out.println(s1 == s3); <span class="comment">// true</span></span><br><span class="line">        System.out.println(s1 == s4); <span class="comment">// true</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        test1();</span><br><span class="line">        test2();</span><br><span class="line">        test3();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="和equals-比较"><a href="#和equals-比较" class="headerlink" title="==和equals()比较"></a>==和equals()比较</h3><ul>
<li>“==”对比的是<strong>栈中的值</strong>。基本类型直接在栈中分配，引用类型是堆中内存对象的地址</li>
<li>equals()<ul>
<li>在Object类中默认采用==，通常会重写</li>
<li>String类重写后直接进行字符串内容的判断，区分大小写</li>
</ul>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//直接赋值过程中，自动保存在堆中的常量池，如果有相同数据定义时可以减少对象的产生</span></span><br><span class="line">String strA = <span class="string">&quot;mldn&quot;</span>;</span><br><span class="line">String strB = <span class="string">&quot;mldn&quot;</span>;</span><br><span class="line">System.out.println(strA==strB);<span class="comment">//true</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//构造方法，会产生两个实例化对象，并且不会自动入池，无法实现对象的重用，但是可以利用intern()方法手工入池处理。</span></span><br><span class="line">String strC = <span class="keyword">new</span> String(<span class="string">&quot;mldn&quot;</span>);</span><br><span class="line">System.out.println(strA==strB);<span class="comment">//false</span></span><br></pre></td></tr></table></figure>

<p><img src="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223434.png" alt="image-20210223222041289"></p>
<p>System.out.println()默认使用toString方法</p>
<h3 id="equals-和hashCode"><a href="#equals-和hashCode" class="headerlink" title="equals()和hashCode()"></a>equals()和hashCode()</h3><p>hashCode()方法和equals()方法都是用来对比两个对象是否相等一致。</p>
<p>因为重写的equals()里一般比较的比较全面比较复杂，这样效率就比较低，而利用hashCode()进行对比，则只要生成一个hash值进行比较就可以了，<strong>效率很高</strong>。</p>
<p>但是hashCode()<strong>并不是完全可靠</strong>，有时候不同的对象他们生成的hashcode也会一样（生成hash值得公式可能存在的问题），所以hashCode()只能说是大部分时候可靠，并不是绝对可靠，即：</p>
<ol>
<li><p>equals()相等的两个对象他们的hashCode()肯定相等，也就是用equals()对比是绝对可靠的。</p>
</li>
<li><p>hashCode()相等的两个对象他们的equals()不一定相等，也就是hashCode()不是绝对可靠的。</p>
</li>
</ol>
<p>所有对于需要大量并且快速的对比的话如果都用equals()去做显然效率太低，所以解决方式是，每当需要对比的时候，<strong>首先用hashCode()去对比</strong>，如果hashCode()不一样，则表示这两个对象肯定不相等（也就是不必再用equals()去再对比了），**如果hashCode()相同，此时再对比他们的equals()**，如果equals()也相同，则表示这两个对象是真的相同了，这样既能大大提高了效率也保证了对比的绝对正确性！</p>
<h5 id="为什么重写equals-一定要重写hashCode"><a href="#为什么重写equals-一定要重写hashCode" class="headerlink" title="为什么重写equals()一定要重写hashCode()"></a>为什么重写equals()一定要重写hashCode()</h5><p>hashCode()默认<strong>返回内存地址</strong>使得不同对象永不相等（equals()默认为==，对比引用类型时也是<strong>返回地址</strong>），为了保证equals()相等时hashCode()一定相等，**重写equals()一定要重写hashCode()**！</p>
<h3 id="正则表达式"><a href="#正则表达式" class="headerlink" title="正则表达式"></a>正则表达式</h3><p>^表示匹配输入的开始，$表示匹配输入的结束，?表示匹配某元素0次或1次</p>
<p>[a-zA-Z\d] 表示匹配一个大小写字母或者数字，\d匹配数字，\w 表示匹配字母数字或下划线， \D 表示匹配一个非数字字符，{m,n}表示最少匹配m次，最多匹配n次。</p>
<p>+表示匹配某元素1次或多次，*表示匹配某元素0次或多次，.可以匹配除了换行符\n \r外的任何单个字符</p>
<h2 id="final关键字"><a href="#final关键字" class="headerlink" title="final关键字"></a>final关键字</h2><ul>
<li>修饰类：类不可被继承</li>
<li>修饰方法：方法不可被重写但可重载</li>
<li>修饰变量：变量被赋值后不能更改<ul>
<li>修饰成员变量：在<strong>声明</strong>时或者<strong>非静态初始化块</strong>或者<strong>构造器</strong>中赋值</li>
<li>修饰类变量：在<strong>声明</strong>时或者<strong>静态初始化块</strong>中赋值</li>
<li>修饰局部变量：在<strong>使用前</strong>赋值即可</li>
<li>修饰基本数据类型：赋值后不能更改</li>
<li>修饰引用型变量：初始化后不能<strong>指向其他对象</strong>，但是<strong>引用的值</strong>可变</li>
</ul>
</li>
</ul>
<h3 id="方法内部类和匿名内部类只能访问局部final变量"><a href="#方法内部类和匿名内部类只能访问局部final变量" class="headerlink" title="方法内部类和匿名内部类只能访问局部final变量"></a>方法内部类和匿名内部类只能访问局部final变量</h3><p>因为内部类和外部类是同一级别的，内部类<strong>不会因为外部类方法执行完毕而销毁</strong>。</p>
<p>当内部类调用外部类方法的局部变量（下图的x）时，为了防止方法结束导致x销毁进而内部类无法使用x，JVM会<strong>复制</strong>一份<strong>局部变量</strong>x到<strong>内部类的成员变量</strong>中。</p>
<p>为了保持局部变量和内部类成员变量的<strong>一致性</strong>，使用final让x无法修改。（是一种妥协）</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">OutClass</span></span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">outPrint</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">final</span> <span class="keyword">int</span> x = <span class="number">10</span>;</span><br><span class="line">        <span class="class"><span class="keyword">class</span> <span class="title">InnerClass</span></span>&#123;</span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">inPrint</span><span class="params">()</span></span>&#123;</span><br><span class="line">                System.out.println(x);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">new</span> InnerClass().inPrint();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="面向对象"><a href="#面向对象" class="headerlink" title="面向对象"></a>面向对象</h2><p>三大特性：<strong>封装、继承、多态</strong></p>
<h3 id="多态"><a href="#多态" class="headerlink" title="多态"></a>多态</h3><ul>
<li>编译多态：方法重载（overload）</li>
<li>运行多态：方法重写（override）</li>
</ul>
<h3 id="继承"><a href="#继承" class="headerlink" title="继承"></a>继承</h3><p><strong>子类重写父类成员方法，只要没有super声明，一律使用子类的。</strong></p>
<p>如*Father a = new Son();*a在方法里调用其他重写方法时默认用到**this.**method()，这个this就代表当前对象，是Son，所以使用子类的</p>
<h4 id="对象转型"><a href="#对象转型" class="headerlink" title="对象转型"></a>对象转型</h4><ul>
<li><p>上转型：向上转型一定是安全的，但是一旦向上转型为父类对象，就不能调用子类原本特有的方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Son extends Father</span></span><br><span class="line">Father fs = <span class="keyword">new</span> Son();</span><br><span class="line">fs.I_am_a_human(); <span class="comment">//调用儿子的重写方法，我是儿子，不是父亲</span></span><br><span class="line">fs.I_am_a_student(); <span class="comment">//编译错误，此方法儿子独有</span></span><br></pre></td></tr></table></figure></li>
<li><p>下转型：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Father fs = <span class="keyword">new</span> Son();</span><br><span class="line"><span class="keyword">if</span>(fs <span class="keyword">instanceof</span> Son)&#123;<span class="comment">//可以使用instanceof关键字判断</span></span><br><span class="line">    Son son = (Son)fs;<span class="comment">//向下转型，容易出错，其实就是转回去了</span></span><br><span class="line">    son.I_am_a_student();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ul>
<h3 id="重载和重写"><a href="#重载和重写" class="headerlink" title="重载和重写"></a>重载和重写</h3><ul>
<li>重载：方法名相同，参数（类型/个数/顺序）不同，返回值和修饰符<strong>可以</strong>不同</li>
<li>重写：方法名参数相同。返回值和抛出异常范围≤父类，访问修饰符≥父类（private方法不能重写）</li>
</ul>
<h2 id="基本类型和包装类"><a href="#基本类型和包装类" class="headerlink" title="基本类型和包装类"></a>基本类型和包装类</h2><h3 id="比较"><a href="#比较" class="headerlink" title="比较"></a>比较</h3><ul>
<li><p>Integer==int会将Integer自动拆箱<strong>比较数值</strong></p>
</li>
<li><p>Integer==Integer，在**[-128,127]<strong>为true（直接引用常量池中的 Integer 对象），否则为false。</strong>除非显示声明new对象**</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Integer a1 = <span class="number">1</span>;</span><br><span class="line">Integer b1 = <span class="number">1</span>;</span><br><span class="line">System.out.println(a1==b1); <span class="comment">//true</span></span><br><span class="line"></span><br><span class="line">Integer a2 = <span class="keyword">new</span> Integer(<span class="number">1</span>);</span><br><span class="line">Integer b2 = <span class="keyword">new</span> Integer(<span class="number">1</span>);</span><br><span class="line">System.out.println(a2==b2);  <span class="comment">// false</span></span><br></pre></td></tr></table></figure></li>
<li><p>Integer.equals(Integer)，首先<strong>比较类型</strong>，再比较值，都相等才为true</p>
</li>
<li><p>Integer.equals(int)，会将int<strong>自动装箱</strong>，再按上一条规则对比</p>
</li>
</ul>
<h3 id="类型转换"><a href="#类型转换" class="headerlink" title="类型转换"></a>类型转换</h3><ol>
<li>通过包装类Integer.toString(123)将整型转换为字符串；</li>
<li>通过Integer.parseInt(str)将字符串转换为int类型；</li>
<li>通过Integer.valueOf(str)把字符串转换为包装类然后通过自动拆箱。</li>
</ol>
<p>int类型可以自动装箱转为Integer，也可以向上转型为double，但不能直接转为Double！</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">double</span> a = <span class="number">1</span>;</span><br><span class="line"><span class="comment">//Double b = 1; 编译错误</span></span><br></pre></td></tr></table></figure>

<h3 id="不同类型的算术运算"><a href="#不同类型的算术运算" class="headerlink" title="不同类型的算术运算"></a>不同类型的算术运算</h3><p>只要两个操作数中有一个是double/float/long类型的，另一个将会被转换成double/float/long类型，并且结果也是double/float/long类型，否则操作数为：byte、short、int 、char，两个数都会被转换成int类型，并且结果也是int类型。<strong>若被声明final 类型不会转换！</strong></p>
<h3 id="BigDecimal"><a href="#BigDecimal" class="headerlink" title="BigDecimal"></a>BigDecimal</h3><p>题目：将一堆String类型的数字累加</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">sum</span><span class="params">(ArrayList&lt;String&gt; numbers)</span> </span>&#123;</span><br><span class="line">    BigDecimal result = <span class="keyword">new</span> BigDecimal(<span class="string">&quot;0&quot;</span>);</span><br><span class="line">    <span class="keyword">for</span> (String str : numbers) &#123;</span><br><span class="line">        BigDecimal bd1 = <span class="keyword">new</span> BigDecimal(str);</span><br><span class="line">        result = result.add(bd1);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result.toString();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="接口和抽象类"><a href="#接口和抽象类" class="headerlink" title="接口和抽象类"></a>接口和抽象类</h2><p>接口字段默认：public static final</p>
<p>接口方法默认：public abstract</p>
<p>接口方法的修饰符可以是：<strong>public，abstract</strong>，default，static（后两者需要有{}）</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">A</span></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> a = <span class="number">1</span>;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> String <span class="title">a</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">default</span> String <span class="title">b</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">static</span> String <span class="title">c</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>抽象类可以有普通成员方法，抽象类只能单继承，接口可以多实现</p>
<h3 id="比较-1"><a href="#比较-1" class="headerlink" title="比较"></a>比较</h3><p>抽象类表达is的关系，奥迪 is a Car，Car包含并实现子类<strong>通用特性</strong>，如run()，其他差异化特性由子类实现，如换挡()</p>
<p>接口表达like的关系，Birds like an aircraft，核心是<strong>定义行为</strong>，不关心具体实现过程。</p>
<h2 id="枚举"><a href="#枚举" class="headerlink" title="枚举"></a>枚举</h2><p>枚举项都是本类的实例，不能用new创建对象，在类外只能使用类名.枚举项</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">enum</span> <span class="title">Direction</span> </span>&#123;</span><br><span class="line">    FRONT, BEHIND, LEFT, RIGHT(<span class="string">&quot;红色&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line">Direction d = Direction.FRONT;</span><br></pre></td></tr></table></figure>

<h3 id="enum与Enum的区别"><a href="#enum与Enum的区别" class="headerlink" title="enum与Enum的区别"></a>enum与Enum的区别</h3><ul>
<li>enum：是从JDK1.5之后提供的一个关键字，用于定义枚举类。</li>
<li>Enum：是一个抽象类，所以使用enum定义的类就默认继承了此类。</li>
</ul>
<h2 id="异常"><a href="#异常" class="headerlink" title="异常"></a>异常</h2><p>Throwable是顶级父类，有Exception和Error子类</p>
<p>try catch只会匹配一个异常处理catch，所以一般范围小的异常放前面。</p>
<h3 id="throw和throws的区别"><a href="#throw和throws的区别" class="headerlink" title="throw和throws的区别"></a>throw和throws的区别</h3><ul>
<li>throw：是在代码块中使用的，主要是手工进行异常对象的抛出；</li>
<li>throws：是在方法定义上使用的，表示将此方法中可能产生的异常明确告诉给调用处，由调用处进行处理。</li>
<li>throws表示出现异常的一种可能性，并不一定会发生这些异常；throw则是抛出了异常，执行throw则一定抛出了某种异常。</li>
</ul>
<p>使用throws关键字来进行异常类型的标注，必须有对应的try.catch处理</p>
<h3 id="try-catch-返回值"><a href="#try-catch-返回值" class="headerlink" title="try{}catch{}返回值"></a>try{}catch{}返回值</h3><p><strong>结论：finally一定会执行，try和finally都有return的话返回finally的；try有return而finally无return则finally修改值无效（catch和finally类似）</strong></p>
<p>属于return之前执行finally</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">test</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> i;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        i = <span class="number">10</span>;</span><br><span class="line">        <span class="keyword">return</span> i;</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        i = <span class="number">20</span>;</span><br><span class="line">        <span class="keyword">return</span> i;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>返回20</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">test</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> i;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        i = <span class="number">10</span>;</span><br><span class="line">        <span class="keyword">return</span> i;</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        i = <span class="number">20</span>;</span><br><span class="line"><span class="comment">//        return i;</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>返回0</p>
<h2 id="内部类"><a href="#内部类" class="headerlink" title="内部类"></a>内部类</h2><p>静态内部类只能访问外围类的<strong>全部静态</strong>属性；普通内部类可以访问外围类的<strong>全部属性</strong></p>
<p>构造方法可以用private，protected，default，private</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Outer</span> </span>&#123;  <span class="comment">//外部类</span></span><br><span class="line">    <span class="keyword">private</span> String msg = <span class="string">&quot;www.mldn.cm&quot;</span>;  <span class="comment">//私有成员属性</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fun</span><span class="params">()</span> </span>&#123; <span class="comment">//普通方法</span></span><br><span class="line">        Inner in  = <span class="keyword">new</span> Inner();  <span class="comment">//实例化内部类对象</span></span><br><span class="line">        in.print();  <span class="comment">//调用内部类方法</span></span><br><span class="line">        System.out.println(in.info); <span class="comment">//访问内部类的私有属性</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="class"><span class="keyword">class</span> <span class="title">Inner</span> </span>&#123;  <span class="comment">//在Outer类的内部定义了Inner类</span></span><br><span class="line">        <span class="keyword">private</span> String info = <span class="string">&quot;今天天气不好，收衣服拉！&quot;</span>;</span><br><span class="line">        <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">print</span><span class="params">()</span></span>&#123; <span class="comment">//此方法只有在外部类能调用</span></span><br><span class="line">            System.out.println(Outer.<span class="keyword">this</span>.msg);  <span class="comment">//Outer里类中的属性</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Outer out = <span class="keyword">new</span> Outer();  <span class="comment">//实例化外部类对象</span></span><br><span class="line">out.fun();  <span class="comment">//调用外部类中的方法</span></span><br><span class="line"></span><br><span class="line">Outer.Inner in = <span class="keyword">new</span> Outer().<span class="function">new <span class="title">Inner</span><span class="params">()</span></span>;</span><br><span class="line"><span class="comment">//in.print();  //此方法无法执行，private</span></span><br></pre></td></tr></table></figure>

<h3 id="静态内部类"><a href="#静态内部类" class="headerlink" title="静态内部类"></a>静态内部类</h3><p>在内部类上使用了static定义，那么这个内部类就变为了“外部类”，就相当于是一个独立的程序类</p>
<p><strong>static定义的不管是类还是方法只能够访问static成员，所以static定义的内部类只能访问外部类中的static属性和方法。</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Outer</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String MSG = <span class="string">&quot;www.mldn.cn&quot;</span>;</span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Inner</span> </span>&#123;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">print</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            System.out.println(Outer.MSG);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Outer.Inner in = <span class="keyword">new</span> Outer.Inner();</span><br><span class="line">in.print();</span><br></pre></td></tr></table></figure>

<h3 id="方法内部类"><a href="#方法内部类" class="headerlink" title="方法内部类"></a>方法内部类</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Outer</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String msg = <span class="string">&quot;www.mldn.cn&quot;</span> ;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fun</span><span class="params">(<span class="keyword">long</span> time)</span> </span>&#123;</span><br><span class="line">        <span class="class"><span class="keyword">class</span> <span class="title">Inner</span> </span>&#123; <span class="comment">//内部类</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">print</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                System.out.println(Outer.<span class="keyword">this</span>.msg);</span><br><span class="line">                System.out.println(time);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">new</span> Inner().print(); <span class="comment">//方法中直接实例化内部类对象</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">JavaDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String args[])</span> </span>&#123;</span><br><span class="line">        <span class="keyword">new</span> Outer().fun(<span class="number">23943342L</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="匿名内部类"><a href="#匿名内部类" class="headerlink" title="匿名内部类"></a>匿名内部类</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">IMessage</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">send</span><span class="params">(String str)</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">JavaDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String args[])</span> </span>&#123;</span><br><span class="line">        IMessage msg = <span class="keyword">new</span> IMessage() &#123;  <span class="comment">//匿名内部类</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">send</span><span class="params">(String str)</span> </span>&#123;</span><br><span class="line">                System.out.println(str);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        msg.send(<span class="string">&quot;www.mldn.cn&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="集合"><a href="#集合" class="headerlink" title="集合"></a>集合</h2><p><strong>Collection</strong> 接口的接口 对象的集合（单列集合）<br>├——-<strong>List</strong> 接口：元素按进入先后有序保存，可重复<br>│—————-├ <strong>LinkedList</strong> 接口实现类，链表，插入删除，没有同步，线程不安全<br>│—————-├ <strong>ArrayList</strong> 接口实现类，数组，随机访问，没有同步，线程不安全<br>│—————-└ <strong>Vector</strong> 接口实现类 数组，同步，线程安全<br>│ ———————-└ <strong>Stack</strong> 是Vector类的实现类<br>└——-<strong>Set</strong> 接口： 仅接收一次，不可重复，并做内部排序<br>├—————-└<strong>HashSet</strong> 数组+链表+红黑树，使用hash表（数组）存储元素<br>│————————└ <strong>LinkedHashSet</strong> 链表维护元素的插入次序<br>└ —————-<strong>TreeSet</strong> 底层实现为红黑树，元素排好序</p>
<p><strong>Map</strong> 接口 键值对的集合 （双列集合）<br>├———<strong>Hashtable</strong> 数组+链表+红黑树，接口实现类， 同步， 线程安全<br>├———<strong>HashMap</strong> 数组+链表+红黑树，接口实现类 ，没有同步， 线程不安全<br>│—————–├ <strong>LinkedHashMap</strong> 双向链表和哈希表实现<br>│—————–└ <strong>WeakHashMap</strong><br>├ ——–<strong>TreeMap</strong> 红黑树(自平衡排序二叉树)对所有的key进行排序，没有同步， 线程不安全<br>└———<strong>IdentifyHashMap</strong></p>
<h3 id="Comparable和Comparator"><a href="#Comparable和Comparator" class="headerlink" title="Comparable和Comparator"></a>Comparable和Comparator</h3><p>用于定义Arrays.sort()时的规则</p>
<ul>
<li><p>Comparable：在<strong>Entity</strong>上实现Comparable接口，里面只有一个compareTo()的方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> <span class="keyword">implements</span> <span class="title">Comparable</span>&lt;<span class="title">Person</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> age;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compareTo</span><span class="params">(Person per)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.age - per.age; <span class="comment">//升序</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Person data[] = <span class="keyword">new</span> Person[]&#123;</span><br><span class="line">        <span class="keyword">new</span> Person(<span class="string">&quot;小强A&quot;</span>, <span class="number">80</span>),</span><br><span class="line">        <span class="keyword">new</span> Person(<span class="string">&quot;小强B&quot;</span>, <span class="number">100</span>),</span><br><span class="line">        <span class="keyword">new</span> Person(<span class="string">&quot;小强C&quot;</span>, <span class="number">50</span>)&#125;;</span><br><span class="line">Arrays.sort(data);</span><br><span class="line">System.out.println(Arrays.toString(data));</span><br></pre></td></tr></table></figure></li>
<li><p>Comparator：在Arrays.sort()中传递<strong>实现Comparator接口的对象</strong>，里面有compare()方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">PersonCompatator</span> <span class="keyword">implements</span> <span class="title">Comparator</span>&lt;<span class="title">Person</span>&gt;</span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(Person p1, Person p2)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> p1.getAge()-p2.getAge();<span class="comment">//升序</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Person data[] = <span class="keyword">new</span> Person[]&#123;</span><br><span class="line">        <span class="keyword">new</span> Person(<span class="string">&quot;小强A&quot;</span>, <span class="number">80</span>),</span><br><span class="line">        <span class="keyword">new</span> Person(<span class="string">&quot;小强B&quot;</span>, <span class="number">100</span>),</span><br><span class="line">        <span class="keyword">new</span> Person(<span class="string">&quot;小强C&quot;</span>, <span class="number">50</span>)&#125;;</span><br><span class="line">Arrays.sort(data, <span class="keyword">new</span> PersonCompatator());</span><br><span class="line">System.out.println(Arrays.toString(data));</span><br></pre></td></tr></table></figure></li>
</ul>
<h3 id="List"><a href="#List" class="headerlink" title="List"></a>List</h3><ol>
<li>ArrayList：底层数据结构是<strong>动态数组</strong>，查询快，增删慢，线程不安全，效率高，可以存储重复元素。在指定初始容量且使用尾插法的情况下，性能甚至超过LinkedList<ul>
<li>扩容：长度超过数组长度（初始化为0插入数据时变成10，超过10就1.5倍）会新建数组，并将数据复制过去</li>
</ul>
</li>
<li>LinkedList 底层数据结构是<strong>双向链表</strong>，查询慢，增删快，线程不安全，效率高，可以存储重复元素。遍历的时候必须用iterator（for循环get(i)为下标访问，性能消耗极大）</li>
<li>Vector: 底层数据结构是<strong>数组</strong>，查询快，增删慢，<strong>线程安全</strong>，效率低，可以存储重复元素</li>
</ol>
<h3 id="Set"><a href="#Set" class="headerlink" title="Set"></a>Set</h3><p>实现唯一性的过程：只有<strong>hashCode()<strong>（先执行）和</strong>equals()<strong>（前者相等才执行）都</strong>相等</strong>才<strong>不存储</strong>。</p>
<h4 id="HashSet"><a href="#HashSet" class="headerlink" title="HashSet"></a>HashSet</h4><p>底层数据结构采用<strong>哈希表</strong>实现，元素<strong>无序且唯一</strong>，线程不安全，效率高，可以存储null元素。</p>
<p>采用哈希算法，底层用数组存储数据。默认初始化容量16，加载因子0.75</p>
<h4 id="TreeSet"><a href="#TreeSet" class="headerlink" title="TreeSet"></a>TreeSet</h4><p>底层数据结构采用<strong>红黑树</strong>来实现，元素<strong>唯一且已经排好序</strong>。</p>
<p>二叉树结构保证了元素的<strong>有序性</strong>。重写<strong>Comparable</strong>接口里面的compareTo()方法来进行排序。</p>
<h3 id="Map"><a href="#Map" class="headerlink" title="Map"></a>Map</h3><h4 id="HashMap"><a href="#HashMap" class="headerlink" title="HashMap"></a>HashMap</h4><p>HashMap的数据结构：数组+链表+红黑树，当链表的值大于8的时候，就会转成红黑树存储。</p>
<p>HashMap默认初始容量16，加载因子0.75，当存储容量大于16*0.75的时候，扩容两倍，并将原数据复制到新的数组上。</p>
<p>HashMap有个静态内部类Entry，该类包含键、值、哈希值和链表的next指向。遍历是无序的，LinkHashMap是其子类，可以使遍历有序。</p>
<p>key为null存在下标为0的位置</p>
<h5 id="元素存储"><a href="#元素存储" class="headerlink" title="元素存储"></a>元素存储</h5><p>两次hash()再模length得到数组下标。<strong>hash%length==hash&amp;(length-1</strong>)的前提是 <strong>length 是 2 的 n 次⽅</strong></p>
<p>插入数据时若位置为空，直接插入。否则判断equals()，相同则覆盖，不同则形成链表。</p>
<p>链表高度达到8</p>
<ul>
<li>数组长度小于64，数组扩容</li>
<li>数组长度长度达到64，链表转化成红黑树，长度低于6将红黑树变回链表</li>
</ul>
<h5 id="线程不安全"><a href="#线程不安全" class="headerlink" title="线程不安全"></a>线程不安全</h5><ul>
<li>假设AB的数据都定位到数组同一个下标，线程A发现元素为空，正准备插入，然后CPU让给线程B，线程B发现也为空，插入数据，然后回到A，A直接覆盖数据导致B插入的数据丢失</li>
<li>扩容</li>
</ul>
<h5 id="扩容"><a href="#扩容" class="headerlink" title="扩容"></a>扩容</h5><p>数组中元素的个数达到负载因子（0.75）*数组长度，扩容2倍。</p>
<p>复制一份数组，迁移数据（重新计算hash()并取模）。</p>
<ul>
<li>对于链表上的数据迁移，1.7为头插法，链表顺序会反过来（尾变成头）。</li>
<li>线程不安全，线程1发现要扩容，A.next = B，A迁移后要迁移B，然后此时阻塞。线程2也发现要扩容，把B迁移过去后，B.next = A，此时A恢复，要继续迁移B，发现已迁移，继续迁移B的下一个，但此时B.next = A，形成闭链，死锁。</li>
<li>故1.8采用尾插法</li>
</ul>
<h5 id="Java7"><a href="#Java7" class="headerlink" title="Java7"></a>Java7</h5><p>数组+链表（头插法，易导致死循环）</p>
<p><img src="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223509.png" alt="image-20210130202021553"></p>
<h5 id="Java8"><a href="#Java8" class="headerlink" title="Java8"></a>Java8</h5><p>数组+链表（尾插法）+红黑树</p>
<p><img src="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223528.png" alt="image-20210130202047812"></p>
<p>Java8在链表超过8个元素时将链表转换成红黑树，降低时间复杂度至O(logN)</p>
<h4 id="ConcurrentHashMap"><a href="#ConcurrentHashMap" class="headerlink" title="ConcurrentHashMap"></a>ConcurrentHashMap</h4><h5 id="Java7-1"><a href="#Java7-1" class="headerlink" title="Java7"></a>Java7</h5><p>使用ReentrantLock+Segment[]（内部类）+HashEntry[]</p>
<img src="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223547.png" alt="image-20210201101846915" style="zoom:50%;" />

<p>由于HashMap线程不安全，使用ConcurrentHashMap，<strong>分段锁</strong>。是一个Segment数组，线程只能轮流访问同一个Segment，每个Segment相当于一个HashMap，有一个HashEntry[]，保存key、value和指向下一个节点的指针。</p>
<p>默认分为16个段，即锁的<strong>并发度</strong>，可以减少锁粒度提升并发性</p>
<h6 id="元素查询"><a href="#元素查询" class="headerlink" title="元素查询"></a>元素查询</h6><p>第一次hash定位到Segment，第二次定位到元素所在链表的头部</p>
<p>put：（2次hash）</p>
<ol>
<li> <strong>计算hash</strong>，<strong>定位到segment</strong>，segment如果是空就先初始化</li>
<li> 使用ReentrantLock加锁，如果获取锁失败则尝试自旋，自旋超过次数就阻塞获取，保证一定获取锁成功</li>
<li> 遍历HashEntry，就是和HashMap一样（<strong>计算hash</strong>，定位到数组中的位置），数组中key和hash一样就直接替换，不存在就再插入链表，链表同样</li>
</ol>
<h5 id="Java8-1"><a href="#Java8-1" class="headerlink" title="Java8"></a>Java8</h5><p>Synchronized+CAS+Node+红黑树</p>
<p>查找替换赋值都用CAS</p>
<h6 id="锁链表的头节点"><a href="#锁链表的头节点" class="headerlink" title="锁链表的头节点"></a>锁链表的头节点</h6><ul>
<li>数组其他元素读写不受影响，锁粒度更细</li>
<li>扩容阻塞所有<strong>写</strong>操作</li>
</ul>
<h6 id="读操作无锁"><a href="#读操作无锁" class="headerlink" title="读操作无锁"></a>读操作无锁</h6><p>Node的val和next使用volatile修饰，保证可见性</p>
<p>数组用volatile修饰，保证扩容可见</p>
<p>put：</p>
<ol>
<li>首先计算hash，遍历node数组，如果node是空的话，就通过CAS+自旋的方式初始化</li>
<li>如果当前数组位置是空则直接通过<strong>CAS自旋写入数据</strong></li>
<li>如果hash==MOVED，说明需要扩容，执行扩容</li>
<li>如果都不满足，就使用synchronized写入数据，写入数据同样判断链表、红黑树，链表写入和HashMap的方式一样，key hash一样就覆盖，反之就尾插法，链表长度超过8就转换成红黑树</li>
</ol>
<p>get:无锁，使用volatile</p>
<h4 id="HashMap和Hashtable区别"><a href="#HashMap和Hashtable区别" class="headerlink" title="HashMap和Hashtable区别"></a>HashMap和Hashtable区别</h4><ul>
<li><p>HashMap是线程不安全的，性能高；HashTable线程安全，性能低</p>
</li>
<li><p>HashMap用迭代器遍历索引从小到大，初始容量16，扩容是容量*2；HashTable用迭代器遍历索引从大到小，初始容量11，扩容是容量*2 +1；</p>
</li>
<li><p>HashMap允许key和value为null，Hashtable不允许</p>
</li>
</ul>
<h2 id="多线程"><a href="#多线程" class="headerlink" title="多线程"></a>多线程</h2><h3 id="进程间的通信IPC"><a href="#进程间的通信IPC" class="headerlink" title="进程间的通信IPC"></a>进程间的通信IPC</h3><ol>
<li>管道(Pipe)：<strong>半双工</strong>的通信方式，管道可用于<strong>具有亲缘关系</strong>进程间的通信，允许一个进程和另一个与它有共同祖先的进程之间进行通信。</li>
<li>命名管道(named pipe)：命名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还<strong>允许无亲缘</strong>关系进程间的通信。命名管道在文件系统中有对应的文件名。命名管道通过命令 mkfifo 或系统调用 mkfifo 来创建。</li>
<li>信号(Signal)：信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进 程间通信外,进程还可以发送信号给进程本身;linux 除了支持 Unix 早期信号语义函数 sigal 外,还支持语义符合 Posix.1 标准的信号函数 sigaction(实际上,该函数是基于 BSD 的,BSD 为了实现可靠信号机制,又能够统一对外接口,用 sigaction 函数重新实现了 signal 函数)。</li>
<li>消息(Message)队列：消息队列是消息的链接表，包括 Posix 消息队列 system V 消息队 列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消 息。消息队列<strong>克服了信号承载信息量少</strong>、<strong>管道只能承载无格式字节流</strong>以及缓冲区大小受限等</li>
<li>共享内存：使得多个进程可以访问同一块内存空间,是<strong>最快的</strong>可用 IPC 形式。是针对其他通信机制运行效率较低而设计的。往往<strong>与其它通信机制如信号量结合使用</strong>，来达到进程间的同步及互斥。 </li>
<li>信号量(semaphore)：基于操作系统的 PV 操作，是一个计数器，常作为<strong>锁机制</strong>，作为<strong>进程间以及同一进程不同线程之间</strong>的<strong>同步</strong>手段。</li>
<li>套接字(Socket)：更为一般的进程间通信机制,可用于<strong>不同机器之间</strong>的进程间通信。起初是由 Unix 系统的 BSD 分支开发出来的，但现在一般可以移植到其它类 Unix 系统上:Linux 和 System V 的变种都支持套接字。</li>
</ol>
<h3 id="线程创建"><a href="#线程创建" class="headerlink" title="线程创建"></a>线程创建</h3><p>Java创建线程的两种方式，启动线程的唯一方法就是通过 **Thread 类的 start()**实例方法。start()方法是一个 native 方法，它将启动一个新线程，并执行 run()方法。</p>
<p><em>直接调用run()起不了多线程，就是普通方法</em></p>
<ol>
<li><p>继承 Thread 类。Thread 类本质上是实现了 Runnable 接口的一个实例。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyThread</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;MyThread.run()&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">MyThread myThread1 = <span class="keyword">new</span> MyThread();</span><br><span class="line">myThread1.start();</span><br></pre></td></tr></table></figure></li>
<li><p>实现 Runnable 接口，此处使用<strong>代理设计模式</strong>，Thread为代理类。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyThread</span> <span class="keyword">extends</span> <span class="title">OtherClass</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;MyThread.run()&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//启动 MyThread 需要首先实例化一个 Thread，并传入自己的 MyThread 实例</span></span><br><span class="line">MyThread myThread = <span class="keyword">new</span> MyThread();</span><br><span class="line">Thread thread = <span class="keyword">new</span> Thread(myThread);</span><br><span class="line"><span class="comment">//Thread 的 run()方法就会调用target.run()</span></span><br><span class="line">thread.start(); </span><br></pre></td></tr></table></figure></li>
<li><p>Callable接口：实现Runnable接口的线程执行完毕后无法获取一个返回值，所以从JDK1.5之后就提出了一个新的接口：java.util.concurrent.Callable接口。Callable定义的时候可以设置一个<strong>泛型</strong>，此泛型的类型就是<strong>返回数据</strong>的类型。Callable还可以<strong>声明抛出异常</strong>。</p>
<p>由于Callable对象不能直接作为Thread的target，可以使用Future接口的实现类<strong>FutureTask</strong>（也实现了Runnable接口）<strong>包装Callable对象</strong>作为target</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyThread</span> <span class="keyword">implements</span> <span class="title">Callable</span>&lt;<span class="title">String</span>&gt;</span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">call</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;线程执行&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RunnableDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception</span>&#123;</span><br><span class="line">        FutureTask&lt;String&gt; task = <span class="keyword">new</span> FutureTask&lt;String&gt;(<span class="keyword">new</span> MyThread());</span><br><span class="line">        <span class="keyword">new</span> Thread(task).start();</span><br><span class="line">        System.out.println(<span class="string">&quot;线程返回数据&quot;</span>+task.get());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<h3 id="线程基本方法"><a href="#线程基本方法" class="headerlink" title="线程基本方法"></a>线程基本方法</h3><p><img src="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223615.png" alt="image-20210131114149829"></p>
<ul>
<li>start()启动线程–&gt;进入就绪态–&gt;运行run()–&gt;运行态</li>
<li>sleep()是Thread类的方法，调用时线程<strong>不释放锁</strong></li>
<li>wait()是Object类的方法，调用时<strong>释放锁</strong>，进入<strong>等待锁定池</strong>，使用notify()后本线程才进入<strong>对象锁定池</strong>准备获取对象锁进入运行状态。方法一般用在同步方法或同步代码块中</li>
<li>yield()会使当前线程让出 CPU 执行时间片，与其他线程一起重新竞争 CPU 时间片</li>
<li>join() ，等待其他线程终止，在当前线程中调用一个线程的 join() 方法，则当前线程转为<strong>阻塞态</strong>，当另一个线程结束，原线程再由阻塞状态变为<strong>就绪态</strong>。方法一般用于主线程启动子线程，并<strong>需要子线程返回结果</strong>，即等待子线程结束后再继续</li>
<li>interrupt()，给这个线程一个通知信号，会影响这个线程内部的一个<strong>中断标识位</strong>，线程本身并<strong>不会改变状态</strong>。当调用sleep()后再调用interrupt()，会抛出 <strong>InterruptedException</strong>，从而使线程提前结束TIMED-WATING 状态。许多抛出该异常的方法在抛出异常前，都会<strong>清除中断标识位</strong>，调用 isInterrupted()方法将会返回 false，从而结束run()，线程结束</li>
<li>notify()，随机唤醒在此对象监视器上等待的一个线程</li>
</ul>
<h3 id="线程死锁的四个必要条件"><a href="#线程死锁的四个必要条件" class="headerlink" title="线程死锁的四个必要条件"></a>线程死锁的四个必要条件</h3><p><strong>1、互斥条件</strong></p>
<p>即一段时间内某资源仅为一个线程所占有，此时若其他线程请求该资源，则请求线程都需要等待。</p>
<p><strong>2、不可剥夺条件</strong></p>
<p>即线程所获得的资源在未使用完毕之前，不能被其他线程强行夺走，只能由获得该资源的线程自己主动释放。</p>
<p><strong>3、请求与保持条件</strong>（吃着碗里的望着锅里的）</p>
<p>即线程已经至少保持了一个资源，但又提出了新的资源请求，而该资源已经被其他线程占有，此时请求线程被阻塞，但对自己已获得的资源保持不放。</p>
<p><strong>4、循环等待条件</strong></p>
<p>存在一种线程资源的循环等待链，链中每一个已获得的资源同时被链中下一个线程所请求。</p>
<h3 id="线程池"><a href="#线程池" class="headerlink" title="线程池"></a>线程池</h3><h5 id="ThreadPoolExecutor"><a href="#ThreadPoolExecutor" class="headerlink" title="ThreadPoolExecutor"></a>ThreadPoolExecutor</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ThreadPoolExecutor(<span class="keyword">int</span> corePoolSize,<span class="keyword">int</span> maximumPoolSize,<span class="keyword">long</span> keepAliveTime,TimeUnit unit,BlockingQueue workQueue ,ThreadFactory threadFactory,RejectedExecutionHandler handler)</span><br></pre></td></tr></table></figure>

<ul>
<li>corePoolSize：线程池基本大小，没有任务执行时池子的大小</li>
<li>maximumPoolSize：线程最大大小，表示可同时活动的线程数量上限</li>
<li>keepAliveTime：线程最大空闲时间，线程空闲时间超过该值将标记为可回收</li>
<li>unit：线程最大空闲时间的时间单位</li>
<li>workQueue：线程队列，该队列满后线程池会创建超出 corePoolSize 大小的线程数量</li>
<li>threadFactory：线程创建工厂，在线程池需要创建一个线程时会用到</li>
<li>hander：拒绝策略，有 AbortPolicy，CallerRunsPolicy，DiscardPolicy，DiscardOldestPolicy</li>
</ul>
<p>任务交到线程池，判断<strong>核心线程数是否已满</strong>，如果未满则<strong>直接创建核心线程</strong>来处理该请求。如果有多于corePoolSize但小于maximumPoolSize线程正在运行，则仅当<strong>队列已满</strong>时才会创建新线程。如果maximumPoolSize达到最大值会执行拒绝策略。</p>
<p><img src="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223644.png" alt="20210307143536"></p>
<h3 id="Java锁"><a href="#Java锁" class="headerlink" title="Java锁"></a>Java锁</h3><ol>
<li>乐观锁，在更新的时候会判断一下在此期间别人有没有去更新这个数据，采取在写时<strong>先读出当前版本号</strong>，然后加锁操作（比较跟上一次的版本号，如果一样则更新），如果失败则要重复读-比较-写的操作。 Java 中的乐观锁基本都是通过 <strong>CAS</strong> 操作实现的，CAS 是一种更新的原子操作，比较当前值跟传入值是否一样，一样则更新，否则失败。</li>
<li>悲观锁，每次在读写数据的时候都会上锁，Java中的悲观锁就是<strong>Synchronized</strong>。</li>
<li>自旋锁，如果持有锁的线程能在很短时间内释放锁资源，等待竞争锁的线程就不需要进入阻塞挂起状态，它们只需要<strong>等一等</strong>（自旋），等持有锁的线程释放锁后即可立即获取锁，这样就避免用户线程和内核的切换的消耗。如果持有锁的线程执行的时间超过自旋等待的最大时间扔没有释放锁，这时争用线程会停止自旋进入阻塞状态。（就是让 cup 在做无用功，锁的竞争不激烈时使用）</li>
<li>Semaphore 信号量，可以控制同时访问的线程个数，通过 acquire() 获取一个许可，如果没有就等待，而 release() 释放一个许可。</li>
<li>可重入锁，为了解决自己锁死自己的情况。如果这个对象没有锁定，或者当前线程已经拥有了这个对象的锁，把锁的计数器+1。可重入就是说某个线程已经获得某个锁，可以再次获取锁而不会出现死锁。</li>
</ol>
<h3 id="Synchronized"><a href="#Synchronized" class="headerlink" title="Synchronized"></a>Synchronized</h3><p>同步锁，可以把任意一个非 NULL 的对象当作锁。他属于独占式的<strong>悲观锁</strong>，同时属于<strong>可重入锁、非公平锁</strong>。<strong>保证可见性和原子性</strong></p>
<p>非公平锁的体现：非公平主要表现在获取锁的行为上，并非是按照申请锁的时间前后给等待线程分配锁的，每当锁被释放后，任何一个线程都有机会竞争到锁，这样做的目的是为了提高执行性能，缺点是可能会产生线程饥饿现象。</p>
<ul>
<li>作用范围：<ul>
<li>作用于方法时，锁住的是对象的实例(this)</li>
<li>当作用于静态方法时，锁住的是Class实例</li>
<li>synchronized 作用于一个对象实例时，锁住的是所有以该对象为锁的代码块</li>
</ul>
</li>
</ul>
<h3 id="ReentrantLock"><a href="#ReentrantLock" class="headerlink" title="ReentrantLock"></a>ReentrantLock</h3><p>ReentantLock 继承接口 Lock 并实现了接口中定义的方法，是一种<strong>可重入锁</strong>，除了能完成 synchronized 所能完成的所有工作外，还提供了诸如可响应中断锁、可轮询锁请求、定时锁等避免多线程死锁的方法。</p>
<h4 id="对比Synchronized"><a href="#对比Synchronized" class="headerlink" title="对比Synchronized"></a>对比Synchronized</h4><p>共同点：</p>
<ul>
<li>都是用来协调多线程对共享对象、变量的访问</li>
<li>都是可重入锁，同一线程可以多次获得同一个锁</li>
<li>都保证了可见性和互斥性</li>
</ul>
<p>不同点：</p>
<ul>
<li><p>ReentrantLock 通过方法 lock()与 unlock()来进行加锁与解锁操作，与 synchronized 会 被 JVM 自动解锁机制不同，ReentrantLock 加锁后需要手动进行解锁。为了避免程序出现异常而无法正常解锁的情况，使用 ReentrantLock 必须在 finally 控制块中进行解锁操作。</p>
</li>
<li><p>ReentrantLock 相比 synchronized 的优势是可中断、<strong>公平锁</strong>、多个锁。这种情况下需要使用ReentrantLock。</p>
</li>
</ul>
<h3 id="volatile关键字"><a href="#volatile关键字" class="headerlink" title="volatile关键字"></a>volatile关键字</h3><p><strong>保证可见性</strong></p>
<p>轻量级同步机制，适合这种场景：一个变量被多个线程共享，线程直接给这个变量赋值。</p>
<img src="https://gitee.com/yuzhenxin/images/raw/master/img/20210307223721.png" alt="image-20210131121958166" style="zoom:50%;" />

<p>如图是对一般变量的读写。而声明变量是 volatile 的话，JVM 保证了每次读变量都从<strong>内存</strong>中读，跳过 CPU cache 这一步。</p>
<ul>
<li>保证可见性：及时通知其他线程本线程对数据的修改</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyTest</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        MyData myData = <span class="keyword">new</span> MyData();</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;线程来了&quot;</span>);</span><br><span class="line">            <span class="comment">// 等待3秒</span></span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            myData.change();</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;更新数值为:&quot;</span> + myData.num);</span><br><span class="line">        &#125;, <span class="string">&quot;A&quot;</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 线程修改后main线程才能获取值为10</span></span><br><span class="line">        <span class="keyword">while</span> (myData.num == <span class="number">0</span>) &#123;</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(Thread.currentThread().getName() + <span class="string">&quot;线程结束，主线程获取数值为:&quot;</span> + myData.num);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyData</span> </span>&#123;</span><br><span class="line">    <span class="keyword">volatile</span> <span class="keyword">int</span> num = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">change</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.num = <span class="number">10</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li><p>原子性</p>
<ul>
<li><p>**i++**不保证原子性，后续线程覆盖前面的值造成丢失写值</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyTest</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        MyData myData = <span class="keyword">new</span> MyData();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">20</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j &lt; <span class="number">1000</span>; j++) &#123;</span><br><span class="line">                    myData.incrase();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, String.valueOf(i)).start();</span><br><span class="line">            ;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 最后用main线程查看结果</span></span><br><span class="line">        <span class="keyword">while</span> (Thread.activeCount() &gt; <span class="number">2</span>) &#123; <span class="comment">// main线程和GC线程</span></span><br><span class="line">            <span class="comment">// 退让</span></span><br><span class="line">            Thread.yield();</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(Thread.currentThread().getName() + </span><br><span class="line">                <span class="string">&quot;\t finally num = &quot;</span> + myData.num); <span class="comment">// 基本不会是20000</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyData</span> </span>&#123;</span><br><span class="line">    <span class="keyword">volatile</span> <span class="keyword">int</span> num = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">incrase</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        num++;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>可使用AtomicInteger解决：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyData</span> </span>&#123;</span><br><span class="line">    AtomicInteger atomicInteger = <span class="keyword">new</span> AtomicInteger();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">incrase</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        atomicInteger.getAndIncrement();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
<li><p>但是对变量的写操作<strong>不依赖于当前值</strong>（如单纯赋值），且该变量没有包含在具有其他变量的不变式中（状态<strong>真正独立于</strong>程序内其他内容）则<strong>可以保证原子性</strong></p>
</li>
</ul>
</li>
<li><p>禁止指令重排：多线程中线程交替执行，由于编译器优化重排（考虑数据依赖关系）的存在，线程间使用的变量未必保持一致性，因此禁止指令重排可避免</p>
</li>
</ul>
<p>内存模型（JMM）：描述规范，不真实存在。每个线程都有一个自己的工作空间（栈），对放在主内存（堆）的共享变量必须拷到自己的工作空间操作再写回主内存</p>
<h3 id="CAS"><a href="#CAS" class="headerlink" title="CAS"></a>CAS</h3><ul>
<li>比较：<ul>
<li>Synchronized悲观锁，保持一致性，并发性下降</li>
<li>CAS<strong>乐观锁</strong>，不加锁保持一致性</li>
</ul>
</li>
<li>简介：依赖Unsafe类，CAS使JVM发出汇编指令，能直接操作内存，不被打断，无线程安全问题。</li>
<li>原理：AtomicInteger的getAndIncrement()保证原子性，依赖Unsafe底层的CAS，判断工作<strong>内存的值</strong>是否为预期主内存的值，是则更新，否则重新获得再次比较 </li>
<li>缺点：<ol>
<li>循环时间长开销大（<strong>自旋</strong>）</li>
<li>只能保证<strong>一个共享变量</strong>的原子操作（方法参数当前对象只有一个）</li>
<li><strong>ABA问题</strong>：拷贝回内存后操作完成再比较有时间差，其他线程可在之前改动后再改回原值<br>解决：<strong>加版本号（时间戳）</strong>–AtomicStampedReference</li>
</ol>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.atomic.AtomicReference;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.atomic.AtomicStampedReference;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyTest</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> AtomicReference&lt;Integer&gt; atomicReference = <span class="keyword">new</span> AtomicReference&lt;Integer&gt;(<span class="number">100</span>);</span><br><span class="line">    <span class="keyword">static</span> AtomicStampedReference&lt;Integer&gt; atomicStampedReference = <span class="keyword">new</span> AtomicStampedReference&lt;Integer&gt;(<span class="number">100</span>, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// ABA问题</span></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            atomicReference.compareAndSet(<span class="number">100</span>, <span class="number">101</span>);</span><br><span class="line">            atomicReference.compareAndSet(<span class="number">101</span>, <span class="number">100</span>);</span><br><span class="line">        &#125;, <span class="string">&quot;t1&quot;</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="comment">// 保证t1完成一次ABA</span></span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(atomicReference.compareAndSet(<span class="number">100</span>, <span class="number">2019</span>) + <span class="string">&quot;\t&quot;</span> + atomicReference.get());</span><br><span class="line">        &#125;, <span class="string">&quot;t2&quot;</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 等t1、t2结束</span></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 解决ABA问题</span></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">int</span> stamp = atomicStampedReference.getStamp();</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t第1次版本号&quot;</span> + stamp);</span><br><span class="line">            <span class="comment">// 保证t1完成一次ABA</span></span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            atomicStampedReference.compareAndSet(<span class="number">100</span>, <span class="number">101</span>, atomicStampedReference.getStamp(),</span><br><span class="line">                    atomicStampedReference.getStamp() + <span class="number">1</span>);</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t第2次版本号&quot;</span> + atomicStampedReference.getStamp());</span><br><span class="line">            atomicStampedReference.compareAndSet(<span class="number">101</span>, <span class="number">100</span>, atomicStampedReference.getStamp(),</span><br><span class="line">                    atomicStampedReference.getStamp() + <span class="number">1</span>);</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t第3次版本号&quot;</span> + atomicStampedReference.getStamp());</span><br><span class="line">        &#125;, <span class="string">&quot;t3&quot;</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">int</span> stamp = atomicStampedReference.getStamp();</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t第1次版本号&quot;</span> + stamp);</span><br><span class="line">            <span class="comment">// 保证t3完成一次ABA</span></span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">3</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            ;</span><br><span class="line">            System.out.println(<span class="string">&quot;t4是否修改成功：&quot;</span> + atomicStampedReference.compareAndSet(<span class="number">100</span>, <span class="number">2019</span>, stamp, stamp + <span class="number">1</span>) + <span class="string">&quot;\t&quot;</span></span><br><span class="line">                    + <span class="string">&quot;当前最新版本号：&quot;</span> + atomicStampedReference.getStamp());</span><br><span class="line">        &#125;, <span class="string">&quot;t4&quot;</span>).start();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>输出：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">true    2019</span><br><span class="line">t3    第1次版本号1</span><br><span class="line">t4    第1次版本号1</span><br><span class="line">t3    第2次版本号2</span><br><span class="line">t3    第3次版本号3</span><br><span class="line">t4是否修改成功：false    当前最新版本号：3</span><br></pre></td></tr></table></figure>

<h3 id="ThreadLocal"><a href="#ThreadLocal" class="headerlink" title="ThreadLocal"></a>ThreadLocal</h3><p>ThreadLocal没有实现任何接口，用于线程间的数据隔离。它会为每个使用该变量的线程提供独立的变量副本，每个线程可以独立地改变自己的副本。</p>
<h3 id="BIO、NIO、AIO"><a href="#BIO、NIO、AIO" class="headerlink" title="BIO、NIO、AIO"></a>BIO、NIO、AIO</h3><p><strong>BIO</strong>：同步阻塞式IO，服务器实现模式为一个连接一个线程，即客户端有连接请求时服务器端就需要启动一个线程进行处理，如果这个连接不做任何事情会造成不必要的线程开销，当然可以通过线程池机制改善。 （<strong>Jedis</strong>）<br><strong>NIO</strong>：同步非阻塞式IO，服务器实现模式为一个请求一个线程，即客户端发送的连接请求都会注册到多路复用器上，多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。（<strong>lettuce</strong>)<br><strong>AIO</strong>：异步非阻塞式IO，服务器实现模式为一个有效请求一个线程，客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。 </p>
<h2 id="反射"><a href="#反射" class="headerlink" title="反射"></a>反射</h2><h3 id="获取反射对象的方法"><a href="#获取反射对象的方法" class="headerlink" title="获取反射对象的方法"></a>获取反射对象的方法</h3><ol>
<li><p>使用new 静态加载</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Person p=<span class="keyword">new</span> Person();</span><br><span class="line">Class clazz=p.getClass();</span><br></pre></td></tr></table></figure></li>
<li><p>调用某个类的 class 属性来获取该类对应的 Class 对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Class clazz=Person.class;</span><br></pre></td></tr></table></figure></li>
<li><p>调用 Class.forName() 方法（最安全/性能最好）</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Class clazz=Class.forName(<span class="string">&quot;类的全路径&quot;</span>);</span><br></pre></td></tr></table></figure></li>
</ol>
<h3 id="题目：通过反射将Map转换成JavaBean的工具类方法"><a href="#题目：通过反射将Map转换成JavaBean的工具类方法" class="headerlink" title="题目：通过反射将Map转换成JavaBean的工具类方法"></a>题目：通过反射将Map转换成JavaBean的工具类方法</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title">mapToObject</span><span class="params">(Map&lt;String, Object&gt; map, Class&lt;?&gt; beanClass)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (map == <span class="keyword">null</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">    Object obj = <span class="keyword">null</span>;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        obj = beanClass.newInstance();</span><br><span class="line">        Field[] fields = obj.getClass().getDeclaredFields();</span><br><span class="line">        <span class="keyword">for</span> (Field field : fields) &#123;</span><br><span class="line">            <span class="keyword">int</span> mod = field.getModifiers();</span><br><span class="line">            <span class="keyword">if</span>(Modifier.isStatic(mod) || Modifier.isFinal(mod))&#123;</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            field.setAccessible(<span class="keyword">true</span>);</span><br><span class="line">            field.set(obj, map.get(field.getName()));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> obj;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="Servlet"><a href="#Servlet" class="headerlink" title="Servlet"></a>Servlet</h2><h3 id="生命周期"><a href="#生命周期" class="headerlink" title="生命周期"></a>生命周期</h3><p>初始化阶段：读取配置文件信息，构造Servlet对象，创建ServletConfig对象</p>
<ol>
<li>Servlet 初始化后调用 init (ServletConfig) 方法。</li>
<li>Servlet 调用 service() 方法来处理客户端的请求。</li>
<li>Servlet 销毁前调用 destroy() 方法。</li>
<li>Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。</li>
</ol>
<h2 id="设计模式"><a href="#设计模式" class="headerlink" title="设计模式"></a>设计模式</h2><h3 id="单例模式"><a href="#单例模式" class="headerlink" title="单例模式"></a>单例模式</h3><ul>
<li>饿汉式：类初始化时直接创建对象，无线程安全问题</li>
<li>懒汉式：延迟创建对象</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Singleton</span></span>&#123;</span><br><span class="line">    <span class="comment">//构造器私有化</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="title">Singleton</span><span class="params">()</span></span>&#123;&#125;</span><br><span class="line">    <span class="comment">//饿汉式</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">private</span> Singleton instance=<span class="keyword">new</span> Singleton();<span class="comment">//因为无法实例化，所以必须是静态的</span></span><br><span class="line">    <span class="function"><span class="keyword">static</span> <span class="keyword">public</span> Singleton <span class="title">getInstance</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> instance;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//懒汉线程安全</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">volatile</span> Singleton instance2;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Singleton <span class="title">getInstance2</span><span class="params">()</span></span>&#123;<span class="comment">//双锁检查，线程安全</span></span><br><span class="line">        <span class="keyword">if</span>(instance2==<span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">synchronized</span> (Singleton.class)&#123;</span><br><span class="line">                <span class="keyword">if</span>(instance2==<span class="keyword">null</span>)</span><br><span class="line">                    instance2=<span class="keyword">new</span> Singleton();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> instance2;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//懒汉2：静态内部类获取</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Singleton2</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="title">Singleton2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//通过方法获取该静态实例</span></span><br><span class="line">    <span class="comment">//加载内部类才创建INSTANCE对象</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Inner</span> </span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Singleton2 INSTANCE = <span class="keyword">new</span> Singleton2();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Singleton2 <span class="title">getInstance</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//此处才创建INSTANCE</span></span><br><span class="line">        <span class="keyword">return</span> Inner.INSTANCE;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>创建对象步骤：<ol>
<li>memory = allocate(); //分配内存空间（留位置给新同学）</li>
<li>instance(memory); //初始化对象（新同学到达）</li>
<li>instance = memory; //设置instance指向该内存地址，instance!=null（看向该位置）<br>由于2和3没有数据依赖关系，多线程下可被重排，instance!=null，但是对象还未初始化完成！因此需加volatile禁止指令重排</li>
</ol>
</li>
</ul>
<h2 id="其他知识点"><a href="#其他知识点" class="headerlink" title="其他知识点"></a>其他知识点</h2><p>&amp;&amp;是短路与，username != null &amp;&amp;!username.equals(“”);</p>

    </div>

    
    
    

      <footer class="post-footer">

        


        
    <div class="post-nav">
      <div class="post-nav-item"></div>
      <div class="post-nav-item">
    <a href="/2020/11/20/%E6%95%B0%E6%8D%AE%E5%BA%93/" rel="next" title="数据库">
      数据库 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#Java%E5%9F%BA%E7%A1%80"><span class="nav-number">1.</span> <span class="nav-text">Java基础</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%AE%89%E8%A3%85"><span class="nav-number">1.1.</span> <span class="nav-text">安装</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#JDK%E3%80%81JRE%E5%92%8CJVM"><span class="nav-number">1.2.</span> <span class="nav-text">JDK、JRE和JVM</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#JVM"><span class="nav-number">1.3.</span> <span class="nav-text">JVM</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#JVM%E7%9A%84%E5%86%85%E5%AD%98%E7%BB%93%E6%9E%84"><span class="nav-number">1.3.1.</span> <span class="nav-text">JVM的内存结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#JVM%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E6%9C%BA%E5%88%B6"><span class="nav-number">1.3.2.</span> <span class="nav-text">JVM垃圾回收机制</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%A0%86%E7%9A%84%E5%88%86%E5%8C%BA"><span class="nav-number">1.3.3.</span> <span class="nav-text">堆的分区</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8"><span class="nav-number">1.4.</span> <span class="nav-text">类加载器</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8F%8C%E4%BA%B2%E5%A7%94%E6%89%98%E6%A8%A1%E5%9E%8B"><span class="nav-number">1.4.1.</span> <span class="nav-text">双亲委托模型</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#String"><span class="nav-number">1.5.</span> <span class="nav-text">String</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#String%E3%80%81StringBuilder%E3%80%81StringBuffer%E7%9A%84%E6%AF%94%E8%BE%83"><span class="nav-number">1.5.1.</span> <span class="nav-text">String、StringBuilder、StringBuffer的比较</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%B8%B8%E9%87%8F%E6%B1%A0"><span class="nav-number">1.5.2.</span> <span class="nav-text">字符串常量池</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%92%8Cequals-%E6%AF%94%E8%BE%83"><span class="nav-number">1.5.3.</span> <span class="nav-text">&#x3D;&#x3D;和equals()比较</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#equals-%E5%92%8ChashCode"><span class="nav-number">1.5.4.</span> <span class="nav-text">equals()和hashCode()</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%87%8D%E5%86%99equals-%E4%B8%80%E5%AE%9A%E8%A6%81%E9%87%8D%E5%86%99hashCode"><span class="nav-number">1.5.4.0.1.</span> <span class="nav-text">为什么重写equals()一定要重写hashCode()</span></a></li></ol></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F"><span class="nav-number">1.5.5.</span> <span class="nav-text">正则表达式</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#final%E5%85%B3%E9%94%AE%E5%AD%97"><span class="nav-number">1.6.</span> <span class="nav-text">final关键字</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%96%B9%E6%B3%95%E5%86%85%E9%83%A8%E7%B1%BB%E5%92%8C%E5%8C%BF%E5%90%8D%E5%86%85%E9%83%A8%E7%B1%BB%E5%8F%AA%E8%83%BD%E8%AE%BF%E9%97%AE%E5%B1%80%E9%83%A8final%E5%8F%98%E9%87%8F"><span class="nav-number">1.6.1.</span> <span class="nav-text">方法内部类和匿名内部类只能访问局部final变量</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1"><span class="nav-number">1.7.</span> <span class="nav-text">面向对象</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%A4%9A%E6%80%81"><span class="nav-number">1.7.1.</span> <span class="nav-text">多态</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BB%A7%E6%89%BF"><span class="nav-number">1.7.2.</span> <span class="nav-text">继承</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%AF%B9%E8%B1%A1%E8%BD%AC%E5%9E%8B"><span class="nav-number">1.7.2.1.</span> <span class="nav-text">对象转型</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%87%8D%E8%BD%BD%E5%92%8C%E9%87%8D%E5%86%99"><span class="nav-number">1.7.3.</span> <span class="nav-text">重载和重写</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%9F%BA%E6%9C%AC%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%8C%85%E8%A3%85%E7%B1%BB"><span class="nav-number">1.8.</span> <span class="nav-text">基本类型和包装类</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%AF%94%E8%BE%83"><span class="nav-number">1.8.1.</span> <span class="nav-text">比较</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2"><span class="nav-number">1.8.2.</span> <span class="nav-text">类型转换</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%B8%8D%E5%90%8C%E7%B1%BB%E5%9E%8B%E7%9A%84%E7%AE%97%E6%9C%AF%E8%BF%90%E7%AE%97"><span class="nav-number">1.8.3.</span> <span class="nav-text">不同类型的算术运算</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#BigDecimal"><span class="nav-number">1.8.4.</span> <span class="nav-text">BigDecimal</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%8E%A5%E5%8F%A3%E5%92%8C%E6%8A%BD%E8%B1%A1%E7%B1%BB"><span class="nav-number">1.9.</span> <span class="nav-text">接口和抽象类</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%AF%94%E8%BE%83-1"><span class="nav-number">1.9.1.</span> <span class="nav-text">比较</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%9E%9A%E4%B8%BE"><span class="nav-number">1.10.</span> <span class="nav-text">枚举</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#enum%E4%B8%8EEnum%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="nav-number">1.10.1.</span> <span class="nav-text">enum与Enum的区别</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%BC%82%E5%B8%B8"><span class="nav-number">1.11.</span> <span class="nav-text">异常</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#throw%E5%92%8Cthrows%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="nav-number">1.11.1.</span> <span class="nav-text">throw和throws的区别</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#try-catch-%E8%BF%94%E5%9B%9E%E5%80%BC"><span class="nav-number">1.11.2.</span> <span class="nav-text">try{}catch{}返回值</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%86%85%E9%83%A8%E7%B1%BB"><span class="nav-number">1.12.</span> <span class="nav-text">内部类</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%9D%99%E6%80%81%E5%86%85%E9%83%A8%E7%B1%BB"><span class="nav-number">1.12.1.</span> <span class="nav-text">静态内部类</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%96%B9%E6%B3%95%E5%86%85%E9%83%A8%E7%B1%BB"><span class="nav-number">1.12.2.</span> <span class="nav-text">方法内部类</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8C%BF%E5%90%8D%E5%86%85%E9%83%A8%E7%B1%BB"><span class="nav-number">1.12.3.</span> <span class="nav-text">匿名内部类</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%9B%86%E5%90%88"><span class="nav-number">1.13.</span> <span class="nav-text">集合</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#Comparable%E5%92%8CComparator"><span class="nav-number">1.13.1.</span> <span class="nav-text">Comparable和Comparator</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#List"><span class="nav-number">1.13.2.</span> <span class="nav-text">List</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Set"><span class="nav-number">1.13.3.</span> <span class="nav-text">Set</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#HashSet"><span class="nav-number">1.13.3.1.</span> <span class="nav-text">HashSet</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#TreeSet"><span class="nav-number">1.13.3.2.</span> <span class="nav-text">TreeSet</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Map"><span class="nav-number">1.13.4.</span> <span class="nav-text">Map</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#HashMap"><span class="nav-number">1.13.4.1.</span> <span class="nav-text">HashMap</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#%E5%85%83%E7%B4%A0%E5%AD%98%E5%82%A8"><span class="nav-number">1.13.4.1.1.</span> <span class="nav-text">元素存储</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#%E7%BA%BF%E7%A8%8B%E4%B8%8D%E5%AE%89%E5%85%A8"><span class="nav-number">1.13.4.1.2.</span> <span class="nav-text">线程不安全</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#%E6%89%A9%E5%AE%B9"><span class="nav-number">1.13.4.1.3.</span> <span class="nav-text">扩容</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#Java7"><span class="nav-number">1.13.4.1.4.</span> <span class="nav-text">Java7</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#Java8"><span class="nav-number">1.13.4.1.5.</span> <span class="nav-text">Java8</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#ConcurrentHashMap"><span class="nav-number">1.13.4.2.</span> <span class="nav-text">ConcurrentHashMap</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#Java7-1"><span class="nav-number">1.13.4.2.1.</span> <span class="nav-text">Java7</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#%E5%85%83%E7%B4%A0%E6%9F%A5%E8%AF%A2"><span class="nav-number">1.13.4.2.1.1.</span> <span class="nav-text">元素查询</span></a></li></ol></li><li class="nav-item nav-level-5"><a class="nav-link" href="#Java8-1"><span class="nav-number">1.13.4.2.2.</span> <span class="nav-text">Java8</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#%E9%94%81%E9%93%BE%E8%A1%A8%E7%9A%84%E5%A4%B4%E8%8A%82%E7%82%B9"><span class="nav-number">1.13.4.2.2.1.</span> <span class="nav-text">锁链表的头节点</span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#%E8%AF%BB%E6%93%8D%E4%BD%9C%E6%97%A0%E9%94%81"><span class="nav-number">1.13.4.2.2.2.</span> <span class="nav-text">读操作无锁</span></a></li></ol></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#HashMap%E5%92%8CHashtable%E5%8C%BA%E5%88%AB"><span class="nav-number">1.13.4.3.</span> <span class="nav-text">HashMap和Hashtable区别</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%A4%9A%E7%BA%BF%E7%A8%8B"><span class="nav-number">1.14.</span> <span class="nav-text">多线程</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%BF%9B%E7%A8%8B%E9%97%B4%E7%9A%84%E9%80%9A%E4%BF%A1IPC"><span class="nav-number">1.14.1.</span> <span class="nav-text">进程间的通信IPC</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BA%BF%E7%A8%8B%E5%88%9B%E5%BB%BA"><span class="nav-number">1.14.2.</span> <span class="nav-text">线程创建</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BA%BF%E7%A8%8B%E5%9F%BA%E6%9C%AC%E6%96%B9%E6%B3%95"><span class="nav-number">1.14.3.</span> <span class="nav-text">线程基本方法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BA%BF%E7%A8%8B%E6%AD%BB%E9%94%81%E7%9A%84%E5%9B%9B%E4%B8%AA%E5%BF%85%E8%A6%81%E6%9D%A1%E4%BB%B6"><span class="nav-number">1.14.4.</span> <span class="nav-text">线程死锁的四个必要条件</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BA%BF%E7%A8%8B%E6%B1%A0"><span class="nav-number">1.14.5.</span> <span class="nav-text">线程池</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#ThreadPoolExecutor"><span class="nav-number">1.14.5.0.1.</span> <span class="nav-text">ThreadPoolExecutor</span></a></li></ol></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Java%E9%94%81"><span class="nav-number">1.14.6.</span> <span class="nav-text">Java锁</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Synchronized"><span class="nav-number">1.14.7.</span> <span class="nav-text">Synchronized</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#ReentrantLock"><span class="nav-number">1.14.8.</span> <span class="nav-text">ReentrantLock</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%AF%B9%E6%AF%94Synchronized"><span class="nav-number">1.14.8.1.</span> <span class="nav-text">对比Synchronized</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#volatile%E5%85%B3%E9%94%AE%E5%AD%97"><span class="nav-number">1.14.9.</span> <span class="nav-text">volatile关键字</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#CAS"><span class="nav-number">1.14.10.</span> <span class="nav-text">CAS</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#ThreadLocal"><span class="nav-number">1.14.11.</span> <span class="nav-text">ThreadLocal</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#BIO%E3%80%81NIO%E3%80%81AIO"><span class="nav-number">1.14.12.</span> <span class="nav-text">BIO、NIO、AIO</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%8D%E5%B0%84"><span class="nav-number">1.15.</span> <span class="nav-text">反射</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%8E%B7%E5%8F%96%E5%8F%8D%E5%B0%84%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%96%B9%E6%B3%95"><span class="nav-number">1.15.1.</span> <span class="nav-text">获取反射对象的方法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%A2%98%E7%9B%AE%EF%BC%9A%E9%80%9A%E8%BF%87%E5%8F%8D%E5%B0%84%E5%B0%86Map%E8%BD%AC%E6%8D%A2%E6%88%90JavaBean%E7%9A%84%E5%B7%A5%E5%85%B7%E7%B1%BB%E6%96%B9%E6%B3%95"><span class="nav-number">1.15.2.</span> <span class="nav-text">题目：通过反射将Map转换成JavaBean的工具类方法</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Servlet"><span class="nav-number">1.16.</span> <span class="nav-text">Servlet</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F"><span class="nav-number">1.16.1.</span> <span class="nav-text">生命周期</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F"><span class="nav-number">1.17.</span> <span class="nav-text">设计模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F"><span class="nav-number">1.17.1.</span> <span class="nav-text">单例模式</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%85%B6%E4%BB%96%E7%9F%A5%E8%AF%86%E7%82%B9"><span class="nav-number">1.18.</span> <span class="nav-text">其他知识点</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">余振鑫</p>
  <div class="site-description" itemprop="description">余振鑫的个人博客</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">9</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
  </nav>
</div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">余振鑫</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://muse.theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Muse</a> 强力驱动
  </div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/muse.js"></script>


<script src="/js/next-boot.js"></script>




  















  

  

</body>
</html>
